package io.ouka.pub.util;


import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.naming.NoNameCoder;
import com.thoughtworks.xstream.io.xml.DomDriver;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

public class XMLUtil {

    /**
     * 将xml报文序列化成对象
     * @param xml
     * @param clz
     * @return
     */
    public static<T> T xmlToObj(String xml, Class<T> clz, String root){
        XStream xStream = new XStream();
        // 自动扫描注解
        xStream.autodetectAnnotations(true);
        // 忽略xml中未知元素
        xStream.ignoreUnknownElements();
        // 指定根节点标签
        xStream.alias(root, clz);
        return (T)xStream.fromXML(xml);
    }

    /**
     * 将xml报文序列化成对象
     * @param xml
     * @param clz
     * @return
     */
    public static Object xmlToObj(String xml, Class<?> clz, String root, XStream xStream){
        // 自动扫描注解
        xStream.autodetectAnnotations(true);
        // 忽略xml中未知元素
        xStream.ignoreUnknownElements();
        // 指定根节点标签
        xStream.alias(root, clz);
        return xStream.fromXML(xml);
    }

    /**
     * 将对象转换为xml报文
     * @param obj
     */
    public static String objToXml(Object obj, String root, String headCode){
        XStream xStream = new XStream(new DomDriver(headCode, new NoNameCoder()));
        // 指定根节点标签
        xStream.alias(root, obj.getClass());
        // 去除字段类型信息
        xStream.aliasSystemAttribute(null, "class");
        // 自动扫描注解
        xStream.autodetectAnnotations(true);
        String xmlHead = "<?xml version=\"1.0\" encoding=\"" + headCode + "\"?>\n";
        String xmlBody = xStream.toXML(obj);
        return xmlHead + xmlBody;
    }

    /**
     * 将对象转换为xml报文
     * @param obj
     */
    public static String objToXml(Object obj, String root){
        XStream xStream = new XStream(new DomDriver("UTF-8", new NoNameCoder()));
        // 指定根节点标签
        xStream.alias(root, obj.getClass());
        // 去除字段类型信息
        xStream.aliasSystemAttribute(null, "class");
        // 自动扫描注解
        xStream.autodetectAnnotations(true);
        String xmlBody = xStream.toXML(obj);
        return xmlBody;
    }

    /**
     * 将对象转换为xml报文
     * @param obj
     */
    public static String objToXml(Object obj, String root, String headCode, XStream xStream){
        // 指定根节点标签
        xStream.alias(root, obj.getClass());
        // 去除字段类型信息
        xStream.aliasSystemAttribute(null, "class");
        // 自动扫描注解
        xStream.autodetectAnnotations(true);
        String xmlHead = "<?xml version=\"1.0\" encoding=\"" + headCode + "\"?>\n";
        String xmlBody = xStream.toXML(obj);
        return xmlHead + xmlBody;
    }

    /**
     * 获取xml指定节点的文本
     * @param xml
     * @param leafNodePath ReqType所在的叶节点路径
     * @return
     * @throws DocumentException
     */
    public static String getTextFromXml(String xml, String leafNodePath) throws DocumentException {
        Document doc = DocumentHelper.parseText(xml);
        Node reqTypeNode = doc.selectSingleNode(leafNodePath);
        return reqTypeNode.getText();
    }

    /**
     * 获取xml指定节点
     * @param xml
     * @param leafNodePath ReqType所在的叶节点路径
     * @return
     * @throws DocumentException
     */
    public static Node getNodeFromXml(String xml, String leafNodePath) throws DocumentException{
        Document doc = DocumentHelper.parseText(xml);
        Node reqTypeNode = doc.selectSingleNode(leafNodePath);
        return reqTypeNode;
    }

    /**
     * xml格式化
     * @param rawXML
     * @param encoding
     * @return
     * @throws DocumentException
     * @throws IOException
     */
    public static String formatXML(String rawXML, String encoding, boolean isCompact) throws DocumentException, IOException {
        SAXReader reader = new SAXReader();
        // 注释：创建一个串的字符输入流
        StringReader in = new StringReader(rawXML);
        Document doc = reader.read(in);
        // 注释：创建输出格式
        OutputFormat formater = null;
        if(isCompact){
            formater = OutputFormat.createCompactFormat();
        }else{
            formater = OutputFormat.createPrettyPrint();
        }
        // 注释：设置xml的输出编码
        formater.setEncoding(encoding);
        // 注释：去除第二行空行
        formater.setNewLineAfterDeclaration(false);
        // 注释：创建输出(目标)
        StringWriter out = new StringWriter();
        // 注释：创建输出流
        XMLWriter writer = new XMLWriter(out, formater);
        // 注释：输出格式化的串到目标中，执行后。格式化后的串保存在out中。
        writer.write(doc);

        writer.close();
        // 注释：返回我们格式化后的结果
        return out.toString();
    }
}
